﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Text;
using Common.Model;
using Common.Util;
using GxTsSharp.Models;
using log4net;
using Quartz.Xml.JobSchedulingData20;

namespace StockIndex
{
    //存放内存数据
    public class MemoryDataDB
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(MemoryDataDB));

        //主题股票dic:主题名=》股票列表
        public static readonly ConcurrentDictionary<String, HashSet<String>> TopicStocks =
            new ConcurrentDictionary<string, HashSet<string>>();

        //主题简单指标集合:主题名=>简单指标
        public static readonly ConcurrentDictionary<String, SimpleIndicatorModel> TopicSimpleIndicatorDic =
            new ConcurrentDictionary<string, SimpleIndicatorModel>();

        //昨日股票市值:股票代码(000001.SZ)=>市值
        public static readonly ConcurrentDictionary<string, decimal>
            DicStockMarketValueYd = new ConcurrentDictionary<string, decimal>();

        //主题各个股票权重:主题名=》（股票代码(000001.SZ)=权重)
        public static readonly ConcurrentDictionary<string, ConcurrentDictionary<string, decimal>>
            DicTopicStockWeight = new ConcurrentDictionary<string, ConcurrentDictionary<string, decimal>>();

        /// <summary>
        /// stockCode=>Queue
        /// </summary>
        private static readonly ConcurrentDictionary<string, LimitQueue<StockReport>>
            StockReportQueues = new ConcurrentDictionary<string, LimitQueue<StockReport>>();

        /// <summary>
        /// 个股涨跌幅，股票代码(000001.SZ）=》涨跌幅 
        /// </summary>
        public static readonly ConcurrentDictionary<string, decimal> DicStockZdf =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic2DaysStockZdfYd =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic4DaysStockZdfYd =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic9DaysStockZdfYd =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic19DaysStockZdfYd =
            new ConcurrentDictionary<string, decimal>();

        /// <summary>
        /// 当日主题涨跌幅：股票代码(000001.SZ）=》涨跌幅 
        /// </summary>
        public static readonly ConcurrentDictionary<String, Decimal> DicTopicZdf =
            new ConcurrentDictionary<string, decimal>();
        public static readonly ConcurrentDictionary<String, Decimal> Dic2DaysTopicZdfYd =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic4DaysTopicZdfYd =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic9DaysTopicZdfYd =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic19DaysTopicZdfYd =
            new ConcurrentDictionary<string, decimal>();
        public static readonly ConcurrentDictionary<String, Decimal> Dic3DaysTopicZdf =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic5DaysTopicZdf =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic10DaysTopicZdf =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, Decimal> Dic20DaysTopicZdf =
            new ConcurrentDictionary<string, decimal>();

        public static readonly ConcurrentDictionary<String, StockReport> StockSnapshoot =
            new ConcurrentDictionary<string, StockReport>();
        
        // 股票代码=》5日成交量之和/股，每日更新一次
        public static readonly ConcurrentDictionary<String, Decimal> Dic5DaysStockAvgVolumn =
            new ConcurrentDictionary<string, decimal>();
        
        // 主题代码=》5日成交量之和/股，每日应更新一次
        public static readonly ConcurrentDictionary<String, Decimal> Dic5DaysTopicAvgVolumn =
            new ConcurrentDictionary<string, decimal>();
        
        // 主题代码=》当日交量/股，定时任务更新
        public static readonly ConcurrentDictionary<String, Decimal> DicTopicVolumn =
            new ConcurrentDictionary<string, decimal>();
        
        // 主题代码=》量比，定时任务更新
        public static readonly ConcurrentDictionary<String, Decimal> DicTopicLiangbi =
            new ConcurrentDictionary<string, decimal>();
        
        //主题代码=》对列
        public static readonly ConcurrentDictionary<String, LimitQueue<decimal>> DicFiveMinuteQueue =
            new ConcurrentDictionary<string, LimitQueue<decimal>>();
        
        public static readonly ConcurrentDictionary<String,Decimal> DicTopicZhangSu = new ConcurrentDictionary<string, decimal>();
        /// <summary>
        /// 刷新主题股票列表
        /// </summary>
        /// <param name="topicStockList"></param>
        public static void FullTopicStocks(List<TopicStockModel> topicStockList)
        {
            if (topicStockList == null || topicStockList.Count == 0)
            {
                //todo 这里可以设置报警的
                Log.Warn($"主题列表数据为空！");
                return;
            }

            TopicStocks.Clear();
            foreach (var model in topicStockList)
            {
                HashSet<String> stocks = TopicStocks.GetOrAdd(model.TopicName, s => new HashSet<string>());
                stocks.Add(model.StockCode);
            }

            Log.Info($"topicStocks size:{TopicStocks.Count}");
        }

        //获取主题的股票列表
        public static HashSet<String> GetTopicStockList(String topicName)
        {
            TopicStocks.TryGetValue(topicName, out var stockList);
            return stockList;
        }

        /// <summary>
        /// 更新个股涨跌幅
        /// </summary>
        /// <param name="stockCode"></param>
        /// <param name="marketId"></param>
        /// <param name="zdf"></param>
        /// <returns></returns>
        public static void AddOrUpdateStockZdf(string stockCode, decimal zdf)
        {
            DicStockZdf.AddOrUpdate(stockCode, zdf, (k, v) => zdf);
        }

        /// <summary>
        /// 获取个股涨跌幅
        /// </summary>
        /// <param name="stockCode">形式如:000001.SZ</param>
        /// <returns></returns>
        public static decimal GetStockZdf(string stockCode)
        {
            DicStockZdf.TryGetValue(stockCode, out var zdf);
            return zdf;
        }

        public static decimal GetNPreviewStockZdf(String stockCode, int nDays)
        {
            decimal zdf;
            switch (nDays)
            {
                case 2:
                    Dic2DaysStockZdfYd.TryGetValue(stockCode, out zdf);
                    return zdf;
                case 4:
                    Dic4DaysStockZdfYd.TryGetValue(stockCode, out zdf);
                    return zdf;
                case 9:
                    Dic9DaysStockZdfYd.TryGetValue(stockCode, out zdf);
                    return zdf;
                case 19:
                    Dic4DaysStockZdfYd.TryGetValue(stockCode, out zdf);
                    return zdf;
                default:
                    throw new Exception("不存在改周期");
            }
        }

        /// <summary>
        /// 更新股票昨日流通市值
        /// </summary>
        /// <param name="stockCode"></param>
        /// <param name="marketValue"></param>
        /// <returns></returns>
        public static void AddOrUpDateStockMarketValue(string stockCode, decimal marketValue)
        {
            DicStockMarketValueYd.AddOrUpdate(stockCode, marketValue, (k, v) => marketValue);
        }

        /// <summary>
        /// 存储股票截面行情
        /// </summary>
        /// <param name="stockKey"></param>
        /// <param name="stockReport"></param>
        public static void AddStockReport(string stockKey, StockReport stockReport)
        {
            LimitQueue<StockReport> limitQueue =
                StockReportQueues.GetOrAdd(stockKey, new LimitQueue<StockReport>(200));
            limitQueue.Add(stockReport);
        }

        /// <summary>
        /// 存储股票截面行情
        /// </summary>
        /// <param name="stockKey"></param>
        /// <param name="stockReport"></param>
        public static void AddStockReports(string stockKey, List<StockReport> stockReport)
        {
            stockReport.Sort((l, r) => (int) (r.Time - l.Time));
            LimitQueue<StockReport> limitQueue =
                StockReportQueues.GetOrAdd(stockKey, new LimitQueue<StockReport>(200));

            limitQueue.AddRange(stockReport);
        }

        /// <summary>
        /// 获取股票界面行情
        /// </summary>
        /// <param name="stockKey"></param>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static List<StockReport> GetStockReports(string stockKey, DateTime dateTime)
        {
            LimitQueue<StockReport> limitQueue =
                StockReportQueues.GetOrAdd(stockKey, new LimitQueue<StockReport>(200));

            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append(dateTime.Hour).Append(dateTime.Minute).Append(dateTime.Second);
            int time = int.Parse(stringBuilder.ToString());

            return limitQueue.GetData().Where(m => m.Time > time).ToList();
        }

        /// <summary>
        /// 获取股票昨日流通市值
        /// </summary>
        /// <param name="stockCode"></param>
        /// <returns></returns>
        public static decimal GetMarketValue(string stockCode)
        {
            DicStockMarketValueYd.TryGetValue(stockCode, out var marketValue);
            return marketValue;
        }

        public static void AddOrUpdateTopicStockWeight(string topicName, string stockCode, decimal weight)
        {
            ConcurrentDictionary<string, decimal> dic = DicTopicStockWeight.GetOrAdd(topicName, new ConcurrentDictionary<string, decimal>());
            dic.AddOrUpdate(stockCode, weight, (k, v) => weight);
        }


        public static void AddOrUpdateTopicZdf(string topicName, decimal zdf)
        {
            DicTopicZdf.AddOrUpdate(topicName, zdf, (k, v) => zdf);
        }
    }
}